#ifndef _ML_BIRCH_DATA_CLUSTERING_H_
#define _ML_BIRCH_DATA_CLUSTERING_H_
#include "MLCommon.h"
#include "MLDataClustering.h"
#include "MLDataSet.h"
#include "MLDataVector.h"
#include "MLDataPoint.h"
_MYLABLIB_BEGIN

///////////////////////////////////////////////////////////////////////////
// CMLClustering_BIRCHMicroCluster
class CMLClustering_BIRCHMicroCluster
{
public:
	// Constructor and Destructor
	CMLClustering_BIRCHMicroCluster(void);
	~CMLClustering_BIRCHMicroCluster(void);

public:
	// Methods
	int Create(const CMLDataSet& dataSet);
	int Insert(const CMLDataPoint& p);
	inline const CMLDataPoint& GetDataPoint(int nIndex) const { return m_DataSet.Get(nIndex); };
	inline const CMLDataVector<double>& GetLS(void) const { return m_vLS; };
	inline const CMLDataVector<double>& GetSS(void) const { return m_vSS; };

	inline CMLDataPoint GetCenter(void) const 
	{ 
		return m_vLS / m_DataSet.Count(); 
	}

	inline double GetRadius(void) const 
	{
		int N = m_DataSet.Count();
		return sqrt(m_pDistFunc->Distance((m_vLS^2) / N, m_vSS / N));
	}

	inline int GetDataPointCount() const { return (int)m_DataSet.Count(); };
	inline bool IsEmpty() const { return GetDataPointCount() == 0; };

	inline void SetDistFunc(IMLDataPointDistanceFunc* func) { m_pDistFunc = func; };
	inline IMLDataPointDistanceFunc* GetDistFunc(void) const { return m_pDistFunc; };

private:
	// Fields
	CMLDataSet  m_DataSet;
	CMLDataVector<double> m_vLS;
	CMLDataVector<double> m_vSS;
	IMLDataPointDistanceFunc* m_pDistFunc;
};

///////////////////////////////////////////////////////////////////////////
// CMLClustering_BIRCHCFTreeNode
class CMLClustering_BIRCHCFTreeNode
{
public:
	// Constructor and Destructor
	CMLClustering_BIRCHCFTreeNode(void);
	~CMLClustering_BIRCHCFTreeNode(void);

public:
	// Methods
	int CreateFromMicroClusters(const CMLClustering_BIRCHMicroCluster* pMicroCluster, int nMicroIndex);
	int CreateFromChildNodes(std::vector<CMLClustering_BIRCHCFTreeNode*>& vpChildNodes);

public:
	// Properties
	inline int  GetMicroClusterIndex() const { return m_nMicroClusterIndex; };
	inline int  GetDatapointCount() const     { return m_nDatapointCount; };
	inline void SetDatapointCount(int nCount) { m_nDatapointCount = nCount; };
	
	inline const CMLDataVector<double>& GetLS() const { return m_vLS; };
	inline const CMLDataVector<double>& GetSS() const { return m_vSS; };
	inline CMLDataVector<double>& GetLS() { return m_vLS; };
	inline CMLDataVector<double>& GetSS() { return m_vSS; };

	inline CMLDataPoint GetCenter(void) const 
	{ 
		return m_vLS / m_nDatapointCount; 
	}

	inline double GetRadius(void) const 
	{
		int N = m_nDatapointCount;
		return sqrt(m_pDistFunc->Distance((m_vLS^2) / N, m_vSS / N));
	}

	inline int GetNumChildNodes() const { return (int)m_vpChildNodes.size(); };
	inline CMLClustering_BIRCHCFTreeNode* GetChildNode(int nIndex) { return m_vpChildNodes[nIndex]; };

	inline void SetParentNode(CMLClustering_BIRCHCFTreeNode* pNode) { m_pParentNode = pNode; };
	inline CMLClustering_BIRCHCFTreeNode* GetParentNode() { return m_pParentNode; };

	inline void SetDistFunc(IMLDataPointDistanceFunc* func) { m_pDistFunc = func; };
	inline IMLDataPointDistanceFunc* GetDistFunc(void) const { return m_pDistFunc; };

private:
	// Fields
	CMLDataVector<double> m_vLS;
	CMLDataVector<double> m_vSS;
	int m_nMicroClusterIndex; // Only for leaf node
	int m_nDatapointCount;
	IMLDataPointDistanceFunc* m_pDistFunc;
	std::vector<CMLClustering_BIRCHCFTreeNode*> m_vpChildNodes;
	CMLClustering_BIRCHCFTreeNode* m_pParentNode;
};

///////////////////////////////////////////////////////////////////////////
// CMLClustering_BIRCHCFTree
class CMLClustering_BIRCHCFTree
{
public:
	// Constructor and Destructor
	CMLClustering_BIRCHCFTree(void);
	~CMLClustering_BIRCHCFTree(void);

public:
	// Methods
	int Create(std::vector<CMLClustering_BIRCHMicroCluster*>& vpMicroClusters, int nLevelFactor);
	int Release(void);
	inline bool IsCreated(void) const { return m_pRootNode != NULL; };
	inline void SetDistFunc(IMLDataPointDistanceFunc* func) { m_pDistFunc = func; };
	inline IMLDataPointDistanceFunc* GetDistFunc(void) const { return m_pDistFunc; };

private:
	// Implementations
	int ClusterParentNodes(std::vector<CMLClustering_BIRCHCFTreeNode*>& vChildNodes);
	int FreeNode(CMLClustering_BIRCHCFTreeNode* pNode);
	
private:
	// Fields
	CMLClustering_BIRCHCFTreeNode* m_pRootNode;
	int m_nLevelFactor;
	IMLDataPointDistanceFunc* m_pDistFunc;

};


///////////////////////////////////////////////////////////////////////////
// CMLClustering_BIRCH
class CMLClustering_BIRCH: public CMLIncrementalDataClustering
{
public:
	// Constructor and Destructor
	CMLClustering_BIRCH(void);
	~CMLClustering_BIRCH(void);

public:
	// Interfaces
	int SetParameters(const std::wstring& wstrParams);
	int Insert(const CMLDataPoint& dataPoint);
	int GetClusters(const std::wstring& params, std::vector<CMLDataCluster>& vClusters);

public:
	// Extra Methods
	int CreateCFTree(void);
	int CreateMacroClusters(int nK, std::vector<CMLDataCluster>& vClusters);

public:
	// Properties
	inline int  GetNumMicroClusters(void)     { return (int)m_vpMicroClusters.size(); };
	inline void SetInitNumMicroClusters(int nNum) { m_nInitMicroClusters = nNum; };
	inline int  GetInitNumMicroClusters(void) const { return m_nInitMicroClusters; };
	inline void SetLevelFactor(int factor)    { m_nLevelFactor = factor; };
	inline int  GetLevelFactor(void) const    { return m_nLevelFactor; };
	inline void SetInitNumber(int nNum)       { m_nDataPointInitNumber = nNum; };
	inline int  GetInitNumber(void) const     { return m_nDataPointInitNumber; };
	inline int  GetTotalPointNumber(void) const { return m_nDataPointTotalNumber; };
	inline bool IsCFTreeCreated(void) const   { return m_CFTree.IsCreated(); };
	inline void SetMaxMicroClusterRadius(double dMax) { m_dMaxMicroClusterRadius = dMax; };
	inline void SetMaxNumMicroClusters(int nMax) { m_nMaxNumMicroClusters = nMax; };

private:
	// Impelementations
	int InitMicroClusters(void);
	int ReleaseMicroClusters(void);
	int InsertToMicroCluster(const CMLDataPoint& dataPoint);
	CMLClustering_BIRCHMicroCluster* FindNearestMicroCluster(const CMLDataPoint& point, double& dDist);
	int MergeClosestTwoMicroClusters(void);
	
private:
	// Fields
	CMLDataSet     m_DataSet;
	CMLClustering_BIRCHCFTree m_CFTree;
	std::vector<CMLClustering_BIRCHMicroCluster*> m_vpMicroClusters;
	int m_nDataPointInitNumber;
	int m_nDataPointTotalNumber;
	int m_nInitMicroClusters;
	int m_nLevelFactor;
	double m_dMaxMicroClusterRadius;
	int m_nMaxNumMicroClusters;
};


_MYLABLIB_END
#endif
